﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ExpressionToWhere
{
    /// <summary>
    /// 处理worker.Id == 1、worker.Id == id整个表达式
    /// </summary>
    internal class BinaryExpressionVisitor : BaseExpressionVisitor
    {
        public BinaryExpressionVisitor()
        {

        }

        public BinaryExpressionVisitor(bool searchNull = true, string dbType = "SqlServer") : base(searchNull, dbType)
        {

        }

        protected override Expression VisitBinary(BinaryExpression node)
        {
            if (node.Left is MemberExpression && IsCompareOperator(node.NodeType))
            {
                sb.Append(InternalGetSql(node));
            }
            else if (node.Left is UnaryExpression unaryExpression1 && unaryExpression1.Operand.GetType().Name.Equals("PropertyExpression") && IsCompareOperator(node.NodeType))
            {
                //解决DateTime>null、DateTime<null、DateTime==null的情况
                sb.Append(InternalGetSql(node));
            }
            else if (IsLogicOperator(node.NodeType))
            {
                //去掉(a=1)这类表达式两侧的括号
                string leftString = node.Left.ToString();
                leftString = Regex.Replace(leftString, "\\([^()]+\\)", match => match.Value.TrimStart('(').TrimEnd(')'));
                var leftClause = ExpressionProcesser.GetWhereClause(node.Left, searchNull, dbType);
                var rightClause = ExpressionProcesser.GetWhereClause(node.Right, searchNull, dbType);
                if (!string.IsNullOrEmpty(leftClause))
                {
                    if (node.Left is BinaryExpression leftBinaryExpression && !leftBinaryExpression.Left.GetType().Name.Equals("PropertyExpression"))
                    {
                        sb.Append($"({leftClause})");
                    }
                    else
                    {
                        sb.Append($"{leftClause}");
                    }
                }

                //当左侧表达式为空时不判断运算符，避免出现“where and Name="***"”的情况
                //当右侧表达式为空时不判断运算符，避免出现“where Name="***" and”的情况
                if (!string.IsNullOrEmpty(leftClause) && !string.IsNullOrEmpty(rightClause))
                {
                    sb.Append($" {GetOperator(node.NodeType)} ");
                }

                if (!string.IsNullOrEmpty(rightClause))
                {
                    //去掉(a=1)这类表达式两侧的括号
                    if (node.Right is BinaryExpression rightBinaryExpression && !rightBinaryExpression.Left.GetType().Name.Equals("PropertyExpression"))
                    {
                        sb.Append($"({rightClause})");
                    }
                    else
                    {
                        sb.Append($"{rightClause}");
                    }
                }
            }
            else
            {
                throw new NotSupportedException($"Unknow BinaryExpression Left:{node.Left.GetType()} Right:{node.Right.GetType()} NodeType:{node.NodeType}");
            }
            return node;
        }

        private string InternalGetSql(BinaryExpression node)
        {
            MemberExpressionVisitor visitor = new MemberExpressionVisitor();
            visitor.Visit(node.Left);
            string fieldName = visitor.GetResult().ToString();
            string oper = GetOperator(node.NodeType);
            string parameterName = ExpressionProcesser.GetPatameterName(visitor.MemberInfo);
            object parameterValue = ExpressionProcesser.GetConstant(node.Right);
            string sql = $"{fieldName}{oper}@{parameterName}";
            if (parameterValue == null)
            {
                if (searchNull)
                {
                    if (oper == "=")
                    {
                        //无论是否参数化查询is null和is not null不做参数化查询
                        sql = $"{fieldName} is null";
                    }
                    else if(oper == "<>")
                    {
                        //无论是否参数化查询is null和is not null不做参数化查询
                        sql = $"{fieldName} is not null";
                    }
                    else
                    {
                        //无论是否参数化查询is null和is not null不做参数化查询
                        sql = $"{fieldName} {oper} null";
                    }
                }
                else
                {
                    sql = "";
                }
            }
            else
            {
                ExpressionProcesser.Parameters.Add($"@{parameterName}", parameterValue);
            }
            return sql;
        }
    }
}
